Graphorall

Back

一次vscode copilot插件fork bomb引起的服务器DoS

  • 摘要#

    2026 年 5 月 10 日凌晨,组里一台 CentOS 服务器突发响应极慢,top 几乎卡死。当晚因 ps 等统计命令同样缓慢,未能定位原因。次日早晨发现用户 yicheng 名下涌现 8 万余个 node / copilot / sh 进程,且 pkill -9 无法抑制。尝试 loginctl terminate-user 无效,最终通过 cgroup 限制用户进程数(pids.max)阻断新进程创建,存量进程以每秒约百个的速度缓慢下降。元凶指向 VS Code SSH Server 配合 Copilot 插件的失控行为。本次故障暴露了 Linux 内核在进程、文件描述符等子系统间缺乏有效隔离的设计缺陷,单一用户的 fork 炸弹或文件句柄耗尽即可引发全局 DoS。


  • 1. 故障现象(2026-05-10 凌晨 1 时)#

    • 用户执行 top 响应极慢,几乎卡死。

    • top 摘要显示:
      Tasks: 165984 total, 62 zombie
      %Cpu(s): 2.5 us, 3.6 sy, 93.8 id
      MiB Mem: 1031898+ total, 84783 free, 566539 used, 380576 buff/cache

    • 当晚尝试使用 ps 配合管道进行复杂统计(如按父进程聚合)时,命令直接卡住无法返回结果。

    • 也尝试排查 Docker 容器、检查文件句柄等,均无明显发现。

  • 2. 第二次排查(次日上午)#

    重启终端后,基础 ps 命令得以执行。按用户统计进程:

    ps -u yicheng -o comm= | sort | uniq -c | sort -nr | head -10
    bash

    输出:

    73266 node
    73259 copilot
    73171 sh
       69 fish
       22 bash
        7 docker
    ...
    plaintext

    结论:用户 yicheng 下存在海量 nodecopilotsh 进程,且数量持续增长。

  • 3. 初步清理尝试(均失败)#

    • 执行 sudo pkill -9 -u yicheng,无明显效果。

    • 再次统计,进程数反而从 7.7 万涨至 8.3 万:

      83241 node
      83234 copilot
      83146 sh
      plaintext
    • 观察到个别 PID 较小的进程即使 kill -9 也无法杀死,状态显示为 S1(可中断睡眠但无法响应信号)。

    • 尝试 sudo loginctl terminate-user yicheng——无效,进程数仍在增长。

      分析:进程创建速度超过杀死速度,仅靠发信号已无法遏制。

  • 4. 最终阻断:cgroup 限制用户进程数#

    • 使用 cgroup v2 限制用户 yicheng 的最大进程数:

      # 获取用户 UID
      id -u yicheng   # 假设 1001
      
      # 设置 pids.max = 500
      echo 500 > /sys/fs/cgroup/user.slice/user-1001.slice/pids.max
      bash
      • 写入后,新进程立即无法创建(任何 fork 返回“资源暂时不可用”)。

      • pkill/killall后,存量进程开始缓慢退出,下降速度约为每秒 100~200 个

        • 但不知是kill的作用还是进程本身超时等主动退出

    • 设置 cgroup 限制后,我自己(yicheng 用户)反而无法登录了

      • 我是通过docker提权到root进行的诊断修复

      • 设置资源限制时必须预留逃生通道,避免将自己锁在门外 在通过 cgroup 限制用户 pids.max 时,若设置的值小于用户当前已有的进程数,任何新建进程(包括登录 shell、ssh 会话、sudo 子进程)都会被立即拒绝,导致该用户无法再登录系统。 实施动态限制前,应先用 ps -u <user> | wc -l 评估当前进程数,设置一个合理上限

  • 5. 恢复情况#

    • 截至发稿,进程数仍在上万级别,以约百个/秒的速度下降。

    • 系统整体负载有所缓解,top 响应恢复至可用状态。

    • 完全清除所有失控进程尚需时间,服务器暂保持运行观察。

  • 6. 根因分析(已确认)#

    • 通过检查用户 yicheng 的进程命令行及工作环境,确定失控进程来源于 VS Code SSH Server(即 code-server 的远程开发会话)及其驱动的 Copilot 插件

    • 具体机制推测:

      • VS Code SSH Server 会在用户登录时启动多个 node 进程,其中包括扩展宿主(Extension Host)。

      • Copilot 插件在后台持续分析代码,可能因工作区过大或内部 bug 导致扩展宿主反复崩溃。

      • 每次崩溃后,VS Code Server 的父进程会重新拉起新的扩展宿主,但旧的 node 进程并未被正确回收(残留为 S 状态)。

      • 由于崩溃频率极高,新进程创建速度远超系统清理速度,最终积累至数万级别。

    • 为什么 pkillloginctl 无效?

      • pkill -9 虽然发送信号,但新进程创建速度更快,表现为“杀不完”。

      • loginctl terminate-user 依赖 systemd 的用户会话管理器,而在进程表极度膨胀时,管理器自身也难以遍历并杀死全部进程树。

  • 7. 经验教训#

    • 极端进程数下,系统瓶颈不在 CPU/内存,而在内核管理开销 本次故障中,系统总进程数超过 16 万,但 CPU 空闲仍有 93.8%,内存也未耗尽。然而 toppspstree 等基础命令几乎卡死,因为管理工具需要遍历 /proc 下数十万个目录,而内核调度器、进程回收等机制在海量进程(即便多数处于 S 状态)下也会产生巨大的元数据开销。这表明 Linux 在面对超大规模进程数时,存在“非资源耗尽型”的性能悬崖——系统并非因 CPU/内存不足而不可用,而是因内核态操作本身的复杂度导致响应瘫痪。

    • 进程创建速度超过杀死速度时,必须先阻断源头 pkill -9 和 loginctl terminate-user 在进程爆炸且持续快速重生时无效。只有通过 cgroup 限制 pids.max 从内核层面阻止新进程创建,才能遏制恶化。这提示管理员应默认启用用户级进程数限制(如 UserTasksMax)。

    • Linux 资源隔离仍不够精细,单点故障易引发全局 DoS 一个用户的失控进程(即便非恶意)即可耗尽全局 pid_max 或 file-max,导致其他用户甚至 root 的基础操作受阻。虽然 cgroup 提供了事后限制的手段,但默认配置下缺乏有效的预防隔离。建议在多用户环境中主动为每个用户或服务设置进程数、文件句柄数的上限。

    • 管理工具在极端负载下的脆弱性 topps 等工具依赖遍历 /proc,当进程数超过 10 万时,这些命令自身可能阻塞数分钟甚至超时。此时应依赖更底层的接口(如直接读取 cgroup 统计)或提前部署监控告警,避免陷入“想排查但工具不可用”的窘境。

  • 附录:关键命令备忘#

    • # 统计用户进程数按命令分组
      ps -u yicheng -o comm= | sort | uniq -c | sort -nr | head
      
      # 限制用户 cgroup 进程数(cgroup v2)
      echo 500 > /sys/fs/cgroup/user.slice/user-$(id -u yicheng).slice/pids.max
      
      # 查看进程状态分布
      ps aux | awk '{print $8}' | sort | uniq -c | sort -nr
      
      # 永久限制用户进程数(/etc/systemd/logind.conf)
      UserTasksMax=1000
      bash

      最后:服务器尚未完全恢复,但已遏制恶化。根本修复需等待 VS Code SSH Server 或 Copilot 插件更新,同时加强系统资源限制策略。

一次vscode copilot插件fork bomb引起的服务器DoS
https://blog.graphorall.top/blog/%E4%B8%80%E6%AC%A1vscode%20copilot%E6%8F%92%E4%BB%B6fork%20bomb%E5%BC%95%E8%B5%B7%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8DoS
Author rubbishzyc
Published at May 10, 2026